Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate different DocumentIds for duplicate generators #64729

Conversation

jasonmalinowski
Copy link
Member

We've seen a few places in the wild where a customer ends up with a generator installed twice into their project. This was causing an issue with how we generate DocumentIds for generated documents: we compute that as a stable hash over some pieces of information so that way we geneate consistent IDs in different processes, and a generated file that disappears due to an edit and comes back can also have the same ID.

The hashing algorithm for a DocumentId included the generator's type name and the generator's assembly name, but if you have two generators with the same assembly name we'd collide. This could happen if you have two different generators with the same name, or your project file is messed up and causing a generator to be added from two different paths at once. This latter case isn't a scenario we support, but this change at least ensures Roslyn won't be throwing exceptions which ends up requiring investigation.

Related to #56619, but doesn't entirely close it, a duplicate generator producing duplicate files will still be confusing. This may also address
#57660 but the belief is there's a race condition there too, as the dumps I've seen don't show duplicate references in the project.

We've seen a few places in the wild where a customer ends up with
a generator installed twice into their project. This was causing an
issue with how we generate DocumentIds for generated documents:
we compute that as a stable hash over some pieces of information so
that way we geneate consistent IDs in different processes, and
a generated file that disappears due to an edit and comes back can also
have the same ID.

The hashing algorithm for a DocumentId included the generator's type
name and the generator's assembly name, but if you have two generators
with the same assembly name we'd collide. This could happen if you
have two different generators with the same name, or your project file
is messed up and causing a generator to be added from two different
paths at once. This latter case isn't a scenario we support, but this
change at least ensures Roslyn won't be throwing exceptions which
ends up requiring investigation.

Related to dotnet#56619, but doesn't
entirely close it, a duplicate generator producing duplicate files
will still be confusing. This may also address
dotnet#57660 but the belief is there's
a race condition there too, as the dumps I've seen don't show duplicate
references in the project.
@jasonmalinowski jasonmalinowski requested a review from a team as a code owner October 14, 2022 00:19
@jasonmalinowski jasonmalinowski self-assigned this Oct 14, 2022
@@ -91,6 +91,28 @@ public async Task WithReferencesMethodCorrectlyUpdatesRunningGenerators()
Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees);
}

// We only run this test on Release, as the compiler has asserts that trigger in Debug that the type names probably shouldn't be the same.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chsienki This is because of the assert that's on the GeneratorDriver constructor...not sure if we want to change it or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, tahts' a bad assert. it should either go or throw.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chsienki let's figure out the plan as a part of #56619, and remember to fix this test with whatever we decide.

@@ -346,7 +346,7 @@ public async ValueTask RefreshFileAsync(CancellationToken cancellationToken)
else
{
// The file isn't there anymore; do we still have the generator at all?
if (project.AnalyzerReferences.Any(a => a.GetGenerators(project.Language).Any(static (g, self) => SourceGeneratorIdentity.GetGeneratorAssemblyName(g) == self._documentIdentity.Generator.AssemblyName, this)))
if (project.AnalyzerReferences.Any(a => a.FullPath == _documentIdentity.Generator.AssemblyPath))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is == ok on filepaths on windows?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally it can be iffy, although in this case the AssemblyPath came from the analzyer reference's path in the first place. I'm going to leave this as is, since at some point this code needs to migrate to potentially run in VS for Mac too, where such a case insensitive comparison would actually be problematic, and no reason to add the extra overhead of the insensitive comparison if not needed.

@jasonmalinowski jasonmalinowski merged commit debdca3 into dotnet:main Oct 14, 2022
@jasonmalinowski jasonmalinowski deleted the support-generators-from-different-paths branch October 14, 2022 17:41
@ghost ghost added this to the Next milestone Oct 14, 2022
@arkalyanms
Copy link
Member

@jasonmalinowski This seems like a 17.5 candidate right? Not 17.4. If there are additional reports of such problems, we can certainly service it. What do you think?

@jasonmalinowski
Copy link
Member Author

@arkalyanms I haven't seen any specific evidence this is impactful for users other than the case where the projects are all broken, so at this point I'm keeping this 17.5 since there's some risk to this change, and it'd be good to kick the tires here. I did write this branch against our 17.4 branch though so if that situation changes it'll be easy to move back to 17.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants